package com.project.core.base;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.Assert;

import com.project.core.utils.DateUtils;

/**
 * 所有DAO的父类，包含有公用的方法，以及简化sql的操作</P>
 * 
 * @author 小满
 *         <P>
 * @since 2014-07-09
 */
public abstract class BaseDAO {

	private static Logger logger = Logger.getLogger(BaseDAO.class);

	@Autowired
	public JdbcTemplate jdbcTemplate;

	/**
	 * 插入数据返回自增主键
	 * <p>
	 * 
	 * @param sql
	 *            - 插入语句 - 参数数组
	 * @return KeyId - 主键
	 */
	public int insertSQLBackKeyId(final String sql, final Object[] object) {
		Assert.notNull(sql, "SQL must not be null");
		Assert.notNull(object, "Object[] must not be null");
		/** generatedKeyHolder是KeyHolder类型，用于获取自动生成的主键或复合主键 */
		KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
		try {
			jdbcTemplate.update(new PreparedStatementCreator() {
				@Override
				public PreparedStatement createPreparedStatement(Connection conn)
						throws SQLException {
					PreparedStatement ps = conn.prepareStatement(sql,
							Statement.RETURN_GENERATED_KEYS);
					for (int i = 0; i < object.length; i++) {
						ps.setObject(i + 1, object[i]);
					}
					return ps;
				}
			}, generatedKeyHolder);
		} catch (Exception e) {
			logger.error("插入sql获取主键失败,失败信息：" + e);
			e.printStackTrace();
		}
		return generatedKeyHolder.getKey().intValue();
	}

	/**
	 * 批量更新操作
	 * <p>
	 * 
	 * @param object
	 *            - SQL数组
	 * @author 小满
	 * @since 2014-07-09
	 */
	public int batchUpdate(final Object[] object) {
		Assert.notNull(object, "Object[] must not be null");
		// 必须初始化数组长度
		String[] updateSQL = new String[object.length];
		int[] updateCount = new int[0];
		try {
			for (int i = 0; i < object.length; i++) {
				// 必须保证 object 不为空才可调用.toString()方法，否则会报空指针
				updateSQL[i] = object.toString();
			}
			updateCount = jdbcTemplate.batchUpdate(updateSQL);
		} catch (Exception e) {
			logger.error("批量更新操作出现异常，异常信息：" + e);
		}
		return updateCount.length;
	}

	/**
	 * 执行可变长度参数的SQL，从而进行插入保存或者更新
	 * <p>
	 * 
	 * @author 小满
	 *         <p>
	 * @since 2014-07-09
	 */
	public int saveOrUpdate(final String sql, Object... objects) {
		return 0;
	}

	/**
	 * 返回clazz类型的对象
	 * 
	 * @param sql
	 * @param args
	 * @param clazz
	 * @return
	 */
	protected <T> T queryForObject(final String sql, final Object[] args,
			final Class<T> clazz) {
		try {
			List<Map<String, Object>> list = this.jdbcTemplate.queryForList(
					sql, args);
			if (list != null && list.size() > 0) {
				Map<String, Object> data = list.get(0);
				if (data != null) {
					T retObj = this.mapObject(data, clazz);
					return retObj;
				}
			}
			return null;
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			// throw new RuntimeException(e);
			return null;
		}
	}

	/**
	 * 返回clazz类型对象List，要求clazz类型的成员变量名与sql中返回的字段名称相同
	 * <p>
	 * 
	 * @param sql
	 * @param args
	 * @param clazz
	 * @return
	 */
	protected <T> List<T> queryForList(final String sql, final Object[] args,
			final Class<T> clazz) {
		List<Map<String, Object>> datas = this.jdbcTemplate.queryForList(sql,
				args);

		List<T> retList = new ArrayList<T>();
		try {
			// 遍历List中的所有数据
			for (Map<String, Object> data : datas) {
				// 以clazz中的成员变量为基准，遍历clazz类型的所有成员变量，依次到Map中取值，然后赋值，
				// 没有取到值的不进行赋值
				T distObj = this.mapObject(data, clazz);
				retList.add(distObj);
			}
			return retList;
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			return null;
			// throw new RuntimeException(e);
		}
	}

	/**
	 * 返回clazz类型的实例，数据来源data，data中的key名称要与clazz的成员变量名称一致
	 * 
	 * @param clazz
	 * @return
	 * @throws
	 * @throws Exception
	 * @paramsql
	 * @paramargs
	 */
	private <T> T mapObject(final Map<String, Object> data, final Class<T> clazz)
			throws Exception {
		// 获取所有成员变量
		Field[] fields = clazz.getDeclaredFields();
		T distObj = clazz.newInstance();
		for (Field field : fields) {
			String fieldName = field.getName();
			Object fieldValue = data.get(fieldName);

			// 如果存在值，则进行赋值
			if (fieldValue != null) {
				PropertyDescriptor pd = new PropertyDescriptor(fieldName, clazz);
				Method setMethod = pd.getWriteMethod();
				// 获取字段类型
				Class<?> type = field.getType();
				if (Integer.class.equals(type)) {
					// Integer
					Integer integerVal = Integer.valueOf(fieldValue.toString());
					setMethod.invoke(distObj, integerVal);
				} else if (Date.class.equals(type)) {
					DateUtils format = DateUtils
							.getInstance("yyyy-MM-dd HH:mm:ss");
					// Date
					setMethod.invoke(distObj,
							format.parse(fieldValue.toString()));
				} else if (Short.class.equals(type)) {
					// Short
					if (fieldValue.getClass().equals(Boolean.class)) {
						if (fieldValue.equals(Boolean.TRUE)) {
							fieldValue = new Integer(1);
						}
						if (fieldValue.equals(Boolean.FALSE)) {
							fieldValue = new Integer(0);
						}
					}
					Short shortVal = Short.valueOf(fieldValue.toString());
					setMethod.invoke(distObj, shortVal);
				} else if (String.class.equals(type)) {
					String fieldValueStr = String.valueOf(fieldValue);
					setMethod.invoke(distObj, fieldValueStr);
				} else {
					setMethod.invoke(distObj, fieldValue);
				}
			}
		}
		return distObj;
	}

}
